%{

#include <stack>
#include <list>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <iostream>

#include "commun.h"
#include "xml/DTDDocument.h"
#include "xml/DTDRule.h"
#include "xml/DTDEntityElement.h"
#include "xml/DTDSimpleRule.h"
#include "xml/DTDComplexRule.h"
#include "xml/XMLDocument.h"
#include "xml/DTDEntityAttList.h"
#include "dtd.tab.h"

using namespace std;

void dtderror(char *msg);
int dtdwrap(void);
int dtdlex(void);
extern XMLDocument * doc;

%}

%error-verbose

%union { 
   char *s;
   DTDDocument * dtddoc;
   DTDRule * r;
}

%token ELEMENT ATTLIST CLOSE OPENPAR CLOSEPAR COMMA PIPE FIXED EMPTY ANY PCDATA AST QMARK PLUS CDATA
%token <s> NAME TOKENTYPE DECLARATION STRING
%type <r> cp name_or_choice_or_seq choice_or_seq cp_plus_seq cp_plus_choice children choice seq contentspec mixed name_plus
%type <dtddoc> dtd
%type <s> cardinality att_definition attribut

%%

main: dtd
    ;

dtd
: dtd ATTLIST NAME att_definition CLOSE
{
	$$ = $1;
	DTDEntityAttList * ent = new DTDEntityAttList("ATTLIST", $3);
	ent->setAttribute($4);
	$$->addDtdAttList(ent);
	doc->setDtdDocument($$);
}
| dtd ELEMENT NAME contentspec CLOSE
{
	$$ = $1;
	DTDEntityElement * entity = new DTDEntityElement("ELEMENT", $3);
	entity->setRule($4);
	$$->addDtdElement(entity);
	doc->setDtdDocument($$);
}
| /* empty */
{
	$$ = new DTDDocument();
}
;

att_definition
: att_definition attribut
{
	$$ = $2;
}
| /* empty */
;

attribut
: NAME att_type defaut_declaration
{
	/* On ne gère que le nom de l'attribut */
	$$ = $1;
}
;

att_type
: CDATA    
| TOKENTYPE
| children
;

contentspec
: children
{
	$$ = $1;
}
| EMPTY
{
	$$ = new DTDSimpleRule("EMPTY");
}
| ANY
{
	$$ = new DTDSimpleRule("ANY");
}
| mixed
{
	$$ = $1;
}
;

mixed
: OPENPAR PCDATA PIPE NAME name_plus CLOSEPAR AST
{
	$$ = $5;
	((DTDComplexRule *) $$)->addRule(new DTDSimpleRule(string($4)));
	((DTDComplexRule *) $$)->addRule(new DTDSimpleRule("#PCDATA"));
	$$->setCardinality(CARD_STAR);
}
| OPENPAR PCDATA CLOSEPAR
{
	$$ = new DTDSimpleRule("#PCDATA");
}
;

name_plus
: name_plus PIPE NAME
{
	$$ = $1;
	((DTDComplexRule *) $$)->addRule(new DTDSimpleRule(string($3)));
}
| /* empty */
{
	$$ = new DTDComplexRule(TYPE_PIPE);
}
;

children
: choice_or_seq cardinality
{
	$$ = $1;
	$$->setCardinality(getCardinalityFromString($2));
}
;

choice_or_seq
: choice
{
	$$ = $1;
}
| seq
{
	$$ = $1;
}
;

cp
: name_or_choice_or_seq cardinality
{
	$$ = $1;
	$$->setCardinality(getCardinalityFromString(string($2)));
}
;

name_or_choice_or_seq
: choice
{
	$$ = $1;
}
| seq
{
	$$ = $1;
}
| NAME
{
	$$ = new DTDSimpleRule(string($1));
}
;

choice
: OPENPAR cp PIPE cp cp_plus_choice CLOSEPAR
{
	$$ = $5;
	((DTDComplexRule*) $$)->addRuleFront($4);
	((DTDComplexRule*) $$)->addRuleFront($2);
}
;

cp_plus_choice
: cp_plus_choice PIPE cp
{
	$$ = $1;
	((DTDComplexRule*) $$)->addRule($3);
}
| /* empty */
{
	$$ = new DTDComplexRule(TYPE_PIPE);
}
;

seq
: OPENPAR cp cp_plus_seq CLOSEPAR
{
	$$ = $3;
	((DTDComplexRule*) $$)->addRuleFront($2);
}
;

cp_plus_seq
: cp_plus_seq COMMA cp
{
	$$ = $1;
	((DTDComplexRule*) $$)->addRule($3);
}
| /* empty */
{
	$$ = new DTDComplexRule(TYPE_COMMA);
}
;

defaut_declaration
: DECLARATION
| STRING
| FIXED STRING
;

cardinality
: PLUS
{
	$$ = (char *) "+";
}
| QMARK
{
	$$ = (char *) "?";
}
| AST
{
	$$ = (char *) "*";
}
| /* empty */
{
	$$ = (char *) "";
}
;

%%

/*
int main(int argc, char **argv)
{
  int err;
  extern int yydebug;
  /*yydebug=1;
  err = yyparse();
  if (err != 0) printf("Parse ended with %d error(s)\n", err);
        else  printf("Parse ended with sucess\n", err);
  return 0;
}
*/

int dtdwrap(void)
{
  return 1;
}

void dtderror(char *msg)
{
  fprintf(stderr, "%s\n", msg);
}
